home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Contributed / SpriteWorld / SpriteWorld Files / Utils / Brian's Extensions / SWTinting.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  11.5 KB  |  374 lines  |  [TEXT/CWIE]

  1. /*  -----------------------------------------------------------------------------------
  2.     -----------------------------------------------------------------------------------
  3.     SWTinting.c
  4.     
  5.     by Brian Roddy
  6.     
  7.     4/3/97
  8.  
  9.  
  10.     - Functions for tinting SpriteWorld graphics a particular color.  
  11.     - Functions for using tinting to implement basic lighting techniques on 
  12.       sprites and tiles.
  13.  
  14.     This style of lighting works well with tiles with a single kind of light.  This
  15.     is because we precompute all of the sprites and tiles at the different light
  16.     levels.  This makes it fast, but not very flexible.  See "SWLightingSquares.c"
  17.     for another approach to lighting which is slightly slower, but is dynamic and
  18.     handles an arbitrary number of colored lights.
  19.  
  20.     This source code is available for free use.
  21.     
  22.     ----------------------------------------------------------------------------------- 
  23.     ----------------------------------------------------------------------------------- */
  24.  
  25. #include <QDOffScreen.h>
  26. #include <SpriteWorldUtils.h>
  27. #include <SWTinting.h>
  28.  
  29.  
  30. /*    --- SWTintFrame
  31.  
  32.     This function takes a frame and uses a color to tint the sprite's frame by some
  33.     percent.  The tint is specified by an RGBColor.  The percent is a number from 0-100.  
  34.     For instance, to lighten a sprite a little bit, use white as a color and 10 as a 
  35.     percent.
  36.     
  37.     These functions perform some basic error checking and will return the error if found.
  38.  
  39. */
  40.  
  41. SW_FUNC OSErr SWTintFrame (
  42.     FramePtr srcFrameP,
  43.     RGBColor* tint, 
  44.     float percent)
  45. {
  46.     GWorldPtr            oldGWld;
  47.     GDHandle            oldGDH;
  48.     GWorldFlags            pixelState;
  49.     RGBColor            opColor;
  50.     OSErr                 err = noErr;
  51.     
  52.         // Make sure we have an actual frame
  53.     if (srcFrameP->framePort == NULL)
  54.         err = paramErr;
  55.  
  56.     if (err == noErr)
  57.     {
  58.             // Save all current information.
  59.         GetGWorld( &oldGWld, &oldGDH );
  60.     
  61.             // Save the pixel state of our bitmap's GWorld
  62.         pixelState = GetPixelsState( GetGWorldPixMap( srcFrameP->framePort ));
  63.         (void)LockPixels( GetGWorldPixMap( srcFrameP->framePort ));
  64.         SetGWorld( srcFrameP->framePort, NULL );
  65.  
  66.             // And then blend in the Sprite image it's appropriate percent.
  67.             // Opcolor specifies the amount of blend
  68.         opColor.red = opColor.blue = opColor.green = (((percent) * 65535.0) / 100.0);
  69.         OpColor(&opColor);
  70.  
  71.             // Paint the Sprite the color specified by tint.
  72.         RGBForeColor(tint);
  73.  
  74.             // Blend will do the work of tinting
  75.         PenMode(blend);
  76.         
  77.  
  78.             // And then paint it to tint the frame.
  79.             // If there is a mask region, then just tint the masked part of the frame.
  80.         if (srcFrameP->maskRgn != NULL) 
  81.         {
  82.             Rect rgnRect = (**srcFrameP->maskRgn).rgnBBox;
  83.             
  84.                 // First move the region to the correct position.
  85.             OffsetRgn(srcFrameP->maskRgn, 
  86.                     srcFrameP->frameRect.left - rgnRect.left + srcFrameP->offsetPoint.h, 
  87.                     srcFrameP->frameRect.top - rgnRect.top + srcFrameP->offsetPoint.v);
  88.             
  89.                 // Then paint it.
  90.             PaintRgn(srcFrameP->maskRgn);
  91.         }
  92.         else
  93.         {        // Otherwise tint the entire frame
  94.             PaintRect(&srcFrameP->frameRect);
  95.             
  96.                 // Now fix the image if we have a pixelMask, since unmasked portions
  97.                 // must be index 0 for the blitters to work properly.
  98.             if (srcFrameP->maskPort != NULL)
  99.             {
  100.                 SWFixImageGWorld(srcFrameP->framePort, srcFrameP->maskPort, (RectPtr) NULL );
  101.             }
  102.         }
  103.         
  104.             // Restore the state of the world.
  105.         PenNormal();
  106.         SetPixelsState( GetGWorldPixMap( srcFrameP->framePort ), pixelState );
  107.         SetGWorld( oldGWld, oldGDH );
  108.     }
  109.  
  110.     SWSetStickyIfError( err );
  111.     return err;
  112. }
  113.  
  114. ///--------------------------------------------------------------------------------------
  115. ///--------------------------------------------------------------------------------------
  116. ///--------------------------------------------------------------------------------------
  117. /// Tile Light Level Functions
  118. ///--------------------------------------------------------------------------------------
  119. short backgroundTileMinimumLightLevel = 0;
  120.  
  121. /*    -- CreateTileBrightnessSetFromCicnResource --
  122.  
  123.     This function is the same as SWLoadTileFromCicnResource except that it will
  124.     create a set of tiles rather than one.  Each tile represents the original tile at a
  125.     different light level.  It uses the SWTintFrame to do this.  Each tile will
  126.     get successively brighter until reaching the original tile.
  127.     
  128. */
  129.  
  130. SW_FUNC OSErr CreateTileBrightnessSetFromCicnResource (
  131.     SpriteWorldPtr    swp,
  132.     short            baseTileID,
  133.     short            cicnID, 
  134.     MaskType        maskType) {
  135.     
  136.     OSErr         err = noErr;
  137.     RGBColor    tintColor;
  138.     int i;
  139.     float ratio;
  140.     
  141.     // Our tint color is black because we make darker versions of the tile
  142.     tintColor.red = tintColor.green = tintColor.blue = 0;
  143.     
  144.     // For each of the different light levels
  145.     for (i = 0; i < kNumberOfBrightnessLevels; i++) {
  146.         if (err == noErr) {
  147.             // Create tile normally            
  148.             err = SWLoadTileFromCicnResource(swp, baseTileID + i, cicnID, maskType, false );
  149.  
  150.             // And then tint it.
  151.             ratio = ((i + 1.0) / kNumberOfBrightnessLevels);
  152.             if ((err == noErr) && (ratio != 1.0)) {
  153.                 err = SWTintFrame(
  154.                             swp->tileFrameArray[baseTileID + i], 
  155.                             &tintColor,
  156.                             100 - (ratio * 100));
  157.             }
  158.         }
  159.     }
  160.     
  161.     SWSetStickyIfError( err );
  162.     return err;
  163. }
  164.  
  165.  
  166. ///--------------------------------------------------------------------------------------
  167. /// GetTileBrightnessLevel
  168. ///
  169. /// Returns a particular tile on the screens light level.
  170. /// Remember that the light level is encoded in the tile's id.
  171.  
  172. SW_FUNC int GetTileBrightnessLevel (SpriteWorldPtr swp, short tileLayer, int row, int col) {
  173.     int curTileID;
  174.         // Compute the current Light level by dividing by 
  175.         // kNumberOfBrightnessLevels and taking the remainder.
  176.     curTileID = swp->tileLayerArray[tileLayer]->tileMap[row][col];
  177.     return (curTileID % kNumberOfBrightnessLevels);
  178. }
  179.  
  180. ///--------------------------------------------------------------------------------------
  181. /// SetTileBrightnessLevel
  182. ///
  183. /// Sets the light level of a particular tile on the screens.
  184. /// Remember that the light level is encoded in the tile's id.
  185.  
  186. SW_FUNC void SetTileBrightnessLevel (SpriteWorldPtr swp, short tileLayer, int row, int col, 
  187.     int level, Boolean relative) {
  188.     int curTileID;
  189.     int oldLightLevel;
  190.     int tileWithoutLight;
  191.     int newLightLevel;
  192.     int newTileID;
  193.     
  194.     // Bounds checking of row and colums.
  195.     if (! ((row < 0) || 
  196.            (col < 0) || 
  197.            (row >= swp->tileLayerArray[tileLayer]->numRows) ||
  198.            (col >= swp->tileLayerArray[tileLayer]->numCols)) ) {
  199.         
  200.         // Given the current TileID
  201.         curTileID = swp->tileLayerArray[tileLayer]->tileMap[row][col];
  202.         
  203.         // Compute the current Light level by dividing by 
  204.         // kNumberOfBrightnessLevels and taking the remainder.
  205.         oldLightLevel = curTileID % kNumberOfBrightnessLevels;
  206.         
  207.         // Subtracting the remainder will leave us with the
  208.         // tile id without light (i.e. the tile at light level zero)
  209.         tileWithoutLight = curTileID - oldLightLevel;
  210.         
  211.         // If relative, add the new level to the old.
  212.         // Of course if the new level is negative it will lower the light.
  213.         if (relative) 
  214.             newLightLevel = oldLightLevel + level;
  215.         else
  216.         // Otherwise, set the light to the maximum of the new or the old.
  217.             newLightLevel = ((level > oldLightLevel) ? level : oldLightLevel);
  218.             
  219.         // Bounds checking of light level
  220.         if (newLightLevel < 0) 
  221.             newLightLevel = 0;
  222.         else if (newLightLevel >= kNumberOfBrightnessLevels) {
  223.             newLightLevel = kNumberOfBrightnessLevels - 1;
  224.         }
  225.         if (newLightLevel < backgroundTileMinimumLightLevel)
  226.             newLightLevel = backgroundTileMinimumLightLevel;
  227.         
  228.         // Compute the new  tile ID  by combining our raw tile id and
  229.         // the new light level. 
  230.         newTileID = tileWithoutLight + newLightLevel;
  231.         swp->tileLayerArray[tileLayer]->tileMap[row][col] = newTileID;
  232.  
  233.         // Then redraw the tile
  234.         SWDrawTile(swp, tileLayer, row, col, newTileID);
  235.     }
  236.     return;
  237. }
  238.  
  239. ///--------------------------------------------------------------------------------------
  240. ///---- LowerTileBrightnessLevels.
  241. ///
  242. /// A utility function to do light fading over time.  Looks pretty neat.
  243.  
  244. SW_FUNC void LowerTileBrightnessLevels (SpriteWorldPtr swp) {
  245.     short    tileRow, tileCol, tileLayer;
  246.     int     numrows = swp->tileLayerArray[0]->numRows;
  247.     int     numcols = swp->tileLayerArray[0]->numCols;
  248.     
  249.         // Go through every TileMap in the SpriteWorld
  250.     for (tileLayer = 0; tileLayer <= swp->lastActiveTileLayer; tileLayer++)
  251.     {
  252.         if (swp->tileLayerArray[tileLayer] == NULL)
  253.             continue;
  254.             
  255.             // Go through every row
  256.         for (tileRow = 0; tileRow < numrows; tileRow++)
  257.         {
  258.                 // and column in the tile map
  259.             for (tileCol = 0; tileCol < numcols; tileCol++)
  260.             {
  261.                     // and lower it by 1.
  262.                 if (GetTileBrightnessLevel(swp, tileLayer, tileRow, tileCol) > 
  263.                     backgroundTileMinimumLightLevel)
  264.                 {
  265.                     SetTileBrightnessLevel(swp, tileLayer, tileRow, tileCol, -1, true);
  266.                 }
  267.             }
  268.         }
  269.     }
  270. }
  271.  
  272.  
  273.  
  274.  
  275. ///--------------------------------------------------------------------------------------
  276. ///--------------------------------------------------------------------------------------
  277. ///--------------------------------------------------------------------------------------
  278. // Sprite Light Level Functions.
  279. ///--------------------------------------------------------------------------------------
  280.  
  281.  
  282. /*    -- CreateSpriteBrightnessSetFromCicnResource --
  283.  
  284.     This function is the same as SWCreateSpriteFromCicnResource except that it will
  285.     create multiple frames for the same sprite where each frame represents a
  286.     different light level.  It uses SWTintFrame to do this.  Each frame will
  287.     get successively brighter until reaching the original sprite's light level.
  288.     
  289. */
  290.  
  291. // Note that this code is a modified version of SWCreateSpriteFromCicnResource.
  292. SW_FUNC OSErr CreateSpriteBrightnessSetFromCicnResource (
  293.     SpriteWorldPtr destSpriteWorld,
  294.     SpritePtr* newSpriteP,
  295.     void* spriteStorageP,
  296.     short cIconID,
  297.     MaskType maskType) {
  298.     
  299.     OSErr             err;
  300.     SpritePtr         tempSpriteP;
  301.     FramePtr         newFrameP;
  302.     short             frame;
  303.     
  304.     // Change #1: Our two new variables
  305.     RGBColor        tintColor;
  306.     float             ratio;
  307.  
  308.     // Change #2: We specify a Tint Color.
  309.     // Our tint color is black because we make are making 
  310.     // darker versions of the sprite
  311.     tintColor.red = tintColor.green = tintColor.blue = 0;
  312.     
  313.     *newSpriteP = NULL;
  314.  
  315.     err = SWCreateSprite(&tempSpriteP, spriteStorageP, kNumberOfBrightnessLevels);
  316.     
  317.     if (err == noErr)
  318.     {
  319.         // Change #3: number of frames we make is kNumberOfBrightnessLevels
  320.         // That is, one frame per brightness level
  321.         for (frame = 0; frame < kNumberOfBrightnessLevels; frame++)
  322.         {
  323.             err = SWCreateFrameFromCicnResource(
  324.                     destSpriteWorld, 
  325.                     &newFrameP, 
  326.                     cIconID, // Change #4: All sprites use the same cicn.
  327.                     maskType);
  328.  
  329.             if (err == noErr) 
  330.                 err = SWAddFrame(tempSpriteP, newFrameP);
  331.  
  332.             // Change #5: Here we do the actual tinting.  We calculate
  333.             // the current percent of brightness and call our tinting
  334.             // function.
  335.             ratio = ((frame + 1.0) / kNumberOfBrightnessLevels);
  336.             if ((err == noErr) && (ratio != 1.0))
  337.             {
  338.                 err = SWTintFrame(
  339.                             tempSpriteP->frameArray[frame], 
  340.                             &tintColor,
  341.                             100 - (ratio * 100));
  342.             }
  343.  
  344.             if (err != noErr)
  345.             {
  346.                 SWDisposeFrame(&newFrameP);
  347.                 SWDisposeSprite(&tempSpriteP);
  348.                 break;
  349.             }
  350.         }
  351.  
  352.         if (err == noErr)
  353.         {
  354.             SWSetSpriteFrameRange(tempSpriteP, 0, kNumberOfBrightnessLevels - 1);
  355.             SWSetCurrentFrameIndex(tempSpriteP, 0);
  356.             *newSpriteP = tempSpriteP;
  357.         }
  358.     }
  359.  
  360.     SWSetStickyIfError( err );
  361.     return err;
  362. }
  363.  
  364. ///--------------------------------------------------------------------------------------
  365. /// The Light Level is encoded in the frame index, so setting and getting it is easy.
  366. SW_FUNC int GetSpriteBrightnessLevel (SpritePtr spriteP) {
  367.     return spriteP->curFrameIndex;
  368. }
  369.  
  370. SW_FUNC void SetSpriteBrightnessLevel (SpritePtr spriteP, int tileLightLevel) {
  371.     SWSetCurrentFrameIndex(spriteP, tileLightLevel);
  372.     return;
  373. }
  374.